Skip to content

使用自定义注解方式实现定时任务(全类型定时任务注解)

创建Factory对象(支持job中自动注入类)

java
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.stereotype.Component;

/**
 * @author luos
 * @date 2019/5/14
 */

@Component
public class QuartzJobFactory extends AdaptableJobFactory {
    //这个对象Spring会帮我们自动注入进来
    @Autowired
    private AutowireCapableBeanFactory capableBeanFactory;

    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        //调用父类的方法
        Object jobInstance = super.createJobInstance(bundle);

        capableBeanFactory.autowireBean(jobInstance);
        return jobInstance;
    }

}

调度任务监听器

实现记录日志的功能

java
import com.commnetsoft.commons.utils.IpUtils;
import com.commnetsoft.dao.QrtzTaskRunLogDao;
import com.commnetsoft.model.QrtzTaskRunLogPo;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * <br> 任务调度 监听器
 *
 * @author luos
 * @date 2020/7/9
 */
@Component
public class TaskJobListener implements JobListener {

    private Logger logger = LoggerFactory.getLogger(TaskJobListener.class);


    @Autowired
    private QrtzTaskRunLogDao qrtzTaskRunLogDao;

    @Override
    public String getName() {
        String name = getClass().getSimpleName();
        return name;
    }

    @Override
    public void jobToBeExecuted(JobExecutionContext context) {
        Scheduler scheduler = context.getScheduler();
        JobDetail jobDetail = context.getJobDetail();
        Trigger trigger = context.getTrigger();

        try {
            QrtzTaskRunLogPo qrtzTaskRunLogPo = new QrtzTaskRunLogPo();
            String hostAddress = IpUtils.getLocalIp();
            qrtzTaskRunLogPo.setSchedname(scheduler.getSchedulerName());
            qrtzTaskRunLogPo.setJobname(jobDetail.getKey().getName());
            qrtzTaskRunLogPo.setJobgroup(jobDetail.getKey().getGroup());
            qrtzTaskRunLogPo.setTriggername(trigger.getKey().getName());
            qrtzTaskRunLogPo.setTriggergroup(trigger.getKey().getGroup());
            qrtzTaskRunLogPo.setRuntype(QrtzTaskRunLogPo.run_auto);
            qrtzTaskRunLogPo.setRunip(hostAddress);
            qrtzTaskRunLogPo.setStarttime(new Date());
            qrtzTaskRunLogDao.insertSelective(qrtzTaskRunLogPo);
            Integer id = qrtzTaskRunLogPo.getId();
            //该任务入库 数据id 传递到任务结束/异常 监听的方法中
            context.put("id", id);
            logger.info("任务[{}],即将开始运行", context.getJobDetail().getKey().getName());
        } catch (SchedulerException e) {
            e.printStackTrace();
        }


    }

    @Override
    public void jobExecutionVetoed(JobExecutionContext context) {
        Object id = context.get("id");
        if (null != id) {
            QrtzTaskRunLogPo qrtzTaskRunLogPo = new QrtzTaskRunLogPo();
            qrtzTaskRunLogPo.setId((Integer) id);
            qrtzTaskRunLogPo.setEndtime(new Date());
            qrtzTaskRunLogPo.setResultcode(QrtzTaskRunLogPo.run_fail);
            qrtzTaskRunLogPo.setResultmsg("在 JobDetail 即将被执行,但又被 TriggerListener 否决了");
            qrtzTaskRunLogDao.updateByPrimaryKeySelective(qrtzTaskRunLogPo);
            logger.info("任务[{}]即将被执行,被 TriggerListener 否决了", context.getJobDetail().getKey().getName());
        }
    }

    @Override
    public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {
        Object id = context.get("id");
        if (null != id) {
            if (null == jobException) {
                QrtzTaskRunLogPo qrtzTaskRunLogPo = new QrtzTaskRunLogPo();
                qrtzTaskRunLogPo.setId((Integer) id);
                qrtzTaskRunLogPo.setConsuming(Integer.valueOf((int) context.getJobRunTime()));
                qrtzTaskRunLogPo.setEndtime(new Date());
                qrtzTaskRunLogPo.setResultcode(QrtzTaskRunLogPo.run_success);
                qrtzTaskRunLogDao.updateByPrimaryKeySelective(qrtzTaskRunLogPo);
                logger.info("任务[{}],运行结束", context.getJobDetail().getKey().getName());
            } else {
                QrtzTaskRunLogPo qrtzTaskRunLogPo = new QrtzTaskRunLogPo();
                qrtzTaskRunLogPo.setId((Integer) id);
                qrtzTaskRunLogPo.setEndtime(new Date());
                qrtzTaskRunLogPo.setResultcode(QrtzTaskRunLogPo.run_fail);
                qrtzTaskRunLogPo.setResultmsg(jobException.getMessage());
                qrtzTaskRunLogDao.updateByPrimaryKeySelective(qrtzTaskRunLogPo);
                logger.info("任务[{}],因异常停止运行", context.getJobDetail().getKey().getName());
            }
        }

//        String message = jobException.getMessage();
//        String message1 = jobException.getCause().getMessage();
//        Throwable cause = jobException.getCause();
    }


}

配置

读取配置文件并注册类和listener

java
 	@Autowired
    DataSource dataSource;

    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(QuartzJobFactory myJobFactory) throws Exception {
        SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
        schedulerFactoryBean.setDataSource(dataSource);
        //使job实例支持spring 容器管理
        schedulerFactoryBean.setOverwriteExistingJobs(true);
        schedulerFactoryBean.setJobFactory(myJobFactory);
        schedulerFactoryBean.setQuartzProperties(quartzProperties());
        // 延迟60s启动quartz
        schedulerFactoryBean.setStartupDelay(10);
        return schedulerFactoryBean;
    }

    @Bean
    public Scheduler scheduler(SchedulerFactoryBean schedulerFactoryBean) throws IOException, SchedulerException {
        Scheduler scheduler = schedulerFactoryBean.getScheduler();
        //创建并注册一个全局的Job Listener
        scheduler.getListenerManager().addJobListener(taskJobListener, EverythingMatcher.allJobs());

        if (!scheduler.isShutdown()) {
            scheduler.start();
            log.info("调度器开始调度任务");
        }
        return scheduler;
    }


    /**
     * 从quartz.properties文件中读取Quartz配置属性
     *
     * @return
     * @throws IOException
     */
    @Bean
    public Properties quartzProperties() throws IOException {
        ArrayList<Resource> configs = new ArrayList<>();
        Resource baseConfig = new ClassPathResource(BASE_QUARTZ_CONFIG);
        if (baseConfig.exists()) {
            log.info("加载Quartz配置文件:{}", baseConfig.toString());
            configs.add(baseConfig);
        }
        Resource extendConfig = new ClassPathResource(QUARTZ_CONFIG);
        if (extendConfig.exists()) {
            log.info("加载Quartz配置文件:{}", extendConfig.toString());
            configs.add(extendConfig);
        }
        Resource extendConfig1 = new FileUrlResource(CONFIG_QUARTZ_CONFIG);
        if (extendConfig1.exists()) {
            log.info("加载Quartz配置文件:{}", extendConfig1.toString());
            configs.add(extendConfig1);
        }
        PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
        propertiesFactoryBean.setLocations(configs.toArray(new Resource[configs.size()]));
        propertiesFactoryBean.afterPropertiesSet();
        Properties properties=propertiesFactoryBean.getObject();
        //判断实例名是否手动设置
        String instanceName=properties.getProperty("org.quartz.scheduler.instanceName");
        if(StringUtils.isBlank(instanceName)){
            properties.setProperty("org.quartz.scheduler.instanceName", applicationName);
        }
        return properties;
    }
properties
#quartz集群配置
# ===========================================================================


<NolebasePageProperties />




# Configure Main Scheduler Properties 调度器属性
# ===========================================================================
#调度标识名 集群中每一个实例都必须使用相同的名称,为空获取项目名
org.quartz.scheduler.instanceName=
#ID设置为自动获取 每一个必须不同
org.quartz.scheduler.instanceId=AUTO
#禁用quartz软件更新
org.quartz.scheduler.skipUpdateCheck=true
#============================================================================
# Configure ThreadPool
#============================================================================
#线程池的实现类(一般使用SimpleThreadPool即可满足几乎所有用户的需求)
#org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
#自定义任务线程池的实现类
org.quartz.threadPool.class =com.commnetsoft.TaskPool
##指定线程数,至少为1(无默认值)(一般设置为1-100直接的整数合适)
#org.quartz.threadPool.threadCount = 1
#设置线程的优先级(最大为java.lang.Thread.MAX_PRIORITY 10,最小为Thread.MIN_PRIORITY 1,默认为5)
#org.quartz.threadPool.threadPriority = 5
#============================================================================
# Configure JobStore
#============================================================================
# 信息保存时间 默认值60秒
org.quartz.jobStore.misfireThreshold = 60000
#数据保存方式为数据库持久化
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
#数据库代理类,一般org.quartz.impl.jdbcjobstore.StdJDBCDelegate可以满足大部分数据库
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#JobDataMaps是否都为String类型
org.quartz.jobStore.useProperties = false
#数据库别名 随便取
org.quartz.jobStore.dataSource = qrtzDS
#表的前缀,默认QRTZ_
org.quartz.jobStore.tablePrefix = QRTZ_
#是否加入集群
org.quartz.jobStore.isClustered = true
#调度实例失效的检查时间间隔
org.quartz.jobStore.clusterCheckinInterval = 20000

#触发事务前是否需要拥有锁
org.quartz.jobStore.acquireTriggersWithinLock=true

流程分析

项目启动时扫描自定义注解入库,并注册到调度器中(创建JobDetail->创建触发器->存入调度器),提供管理接口,并创建监听器,在调度任务执行前、取消、执行后执行。

自定义注解

java
import com.commnetsoft.annotation.TriggerCalendarInterval;

import java.lang.annotation.*;

/**
 * 日历间隔触发器集合
 * CalendarIntervalTrigger 触发器集合
 *
 * @author Brack.zhu
 * @date 2020/6/23
 */
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TriggerCalendarIntervalGroup {

    TriggerCalendarInterval[] value() default {};
}



import com.commnetsoft.annotation.TriggerCron;

import java.lang.annotation.*;

/**
 * Corn表达式触发器集合
 * @author Brack.zhu
 * @date 2020/6/23
 */
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TriggerCronGroup {
    
    TriggerCron[] value() default {};
}



import com.commnetsoft.annotation.TriggerDailyTimeInterval;

import java.lang.annotation.*;

/**
 * 每天时间段间隔触发器集合
 * DailyTimeIntervalTrigger触发器集合
 *
 * @author Brack.zhu
 * @date 2020/6/23
 */
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TriggerDailyTimeIntervalGroup {

    TriggerDailyTimeInterval[] value() default {};
}



import com.commnetsoft.annotation.TriggerSimple;

import java.lang.annotation.*;

/**
 * 简单的触发器集合
 * @author Brack.zhu
 * @date 2020/6/23
 */
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TriggerSimpleGroup {

    TriggerSimple[] value() default {};

}



import java.lang.annotation.*;

/**
 * 任务job<br/>
 * 任务要完整运行还需和触发器(Trigger)配合,一个任务支持多个触发器<br/>
 * <p>如:
 * <blockquote><pre>
 *  {@code
 *     @Task(desc = "测试任务")
 *     @CronTrigger(name = "1", cron = "0 0/1 * * * ?")
 *     @CronTrigger(name = "2", cron = "10 5 * * * ?")
 *     @CalendarIntervalTrigger(name = "3", repeatInterval = 1, repeatIntervalUnit = DateBuilder.IntervalUnit.HOUR)
 *     public class TestTask implements Job {//TODO}
 * }
 *       </pre></blockquote>
 * <p>
 *
 * @author luos
 * @date 2019/7/17
 */

@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface JobTask {
    /**
     * 任务名称
     * 默认为空使用类名 <br/>
     */
    String name() default "";

    /**
     * 任务分组
     * 默认为空使用包路径 <br/>
     */
    String group() default "";

    /**
     * 任务描述
     */
    String desc() default "";

    /**
     * 触发器JobDataMap<br/>
     * 创建JobDataMap在@Configuration中使用@Bean创建的对象名
     *
     * @return
     */
    String dataMap() default "";
}



import java.lang.annotation.*;

/**
 * 触发器时间范围注解
 * @author Brack.zhu
 * @date 2020/6/23
 */
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TimeLimit {

    /**
     * 开始时间,1970年1月1日00:00:00.000 GMT之后的毫秒数<br/>
     *  -1:创建时时间
     * @return
     */
    long start() default -1;

    /**
     * 结束时间,1970年1月1日00:00:00.000 GMT之后的毫秒数
     * @return
     */
    long end() default Long.MAX_VALUE;

}



import com.commnetsoft.annotation.group.TriggerCalendarIntervalGroup;
import org.quartz.DateBuilder;

import java.lang.annotation.*;

/**
 * 日历间隔触发器
 * 类似于SimpleTrigger,以一定的时间间隔执行的任务。 但是不同的是SimpleTrigger指定的时间间隔为毫秒,没办法指定每隔一个月执行一次(每月的时间间隔不是固定值),而CalendarIntervalTrigger支持的间隔单位有秒,分钟,小时,天,月,年,星期。
 * <p>
 * 相较于SimpleTrigger有两个优势:
 * <p>
 * 1、更方便,比如每隔1小时执行,你不用自己去计算1小时等于多少毫秒。
 * <p>
 * 2、支持不是固定长度的间隔,比如间隔为月和年。但劣势是精度只能到秒。
 *
 * @author Brack.zhu
 * @date 2020/6/23
 */
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(TriggerCalendarIntervalGroup.class)
public @interface TriggerCalendarInterval {

    /**
     * 触发器名称
     *
     * @return
     */
    String name();

    /**
     * 间隔时间
     *
     * @return
     */
    int repeatInterval();

    /**
     * 间隔时间单位类型
     *
     * @return
     */
    DateBuilder.IntervalUnit repeatIntervalUnit();

    /*--------------------------------以下非必填-------------------------------------------*/

    /**
     * 触发器描述
     * @return
     */
    String description() default "";

    /**
     * 触发器包含、排除 日历<br/>
     * 详见
     * {@link TriggerCron#modifiedByCalendar()}
     *
     * @return
     */
    String modifiedByCalendar() default "";

    /**
     * 触发器有效期
     *
     * @return
     */
    TimeLimit timeLimit() default @TimeLimit;

    /**
     * 触发器JobDataMap<br/>
     * 创建JobDataMap在@Configuration中使用@Bean创建的对象名
     *
     * @return
     */
    String dataMap() default "";

    /**
     * 错过调度策略机制<br/>
     * MISFIRE_INSTRUCTION_DO_NOTHING<br/>
     * <blockquote>
     * 不触发等下次<br/>
     * </blockquote>
     * MISFIRE_INSTRUCTION_FIRE_ONCE_NOW<br/>
     * <blockquote>
     * 立刻执行一次,然后就按照正常的计划执行。<br/>
     * </blockquote>
     * MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY<br/>
     * <blockquote>
     * 忽略所有的超时状态,按照触发器的策略执行。
     * </blockquote>
     * <p>
     * <p>
     * withMisfireHandlingInstructionIgnoreMisfires
     *
     * @return
     */
    int misfire() default org.quartz.CalendarIntervalTrigger.MISFIRE_INSTRUCTION_DO_NOTHING;


}



import com.commnetsoft.annotation.group.TriggerCronGroup;

import java.lang.annotation.*;

/**
 * Corn表达式触发器
 * @author Brack.zhu
 * @date 2020/6/23
 */
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(TriggerCronGroup.class)
public @interface TriggerCron {

    /**
     * 触发器名称
     * 默认使用类名加触发器名称用 # 拼接 <br/>
     * @return
     */
    String name();

    /**
     * Corn表达式
     * @return
     */
    String cron();

    /*--------------------------------以下非必填-------------------------------------------*/

    /**
     * 触发器描述
     * @return
     */
    String desc() default "";

    /**
     * 触发器包含、排除 日历<br/>
     * 一般为节假日日历,如:<br/>
     * 排除:任务定义工作日周一到周五运行,但是遇到法定节假日(国庆),任务需支持排除指定日期。<br/>
     * 包含:任务定义工作日周一到周五运行,由于法定节假日需要调休,某个周六为工作日,任务需要支持包含指定日期。<br/>
     * 创建日历在@Configuration中使用@Bean
     * <p>如:
     * <blockquote><pre>
     *     {@code
     *     @Bean
     *     public MonthlyCalendar myHolidays(){
     *         MonthlyCalendar calendar=new MonthlyCalendar();
     *         //排除
     *         calendar.setDayExcluded(20,true);
     *         //包含
     *         calendar.setDayExcluded(21,false);
     *         return calendar;
     *     }
     *     }
     *     </pre></blockquote>
     * <p>
     * 日历类型
     * <blockquote><pre>
     * AnnualCalendar	指定每年的哪一天。使用方式如上例。精度是【天】
     * CronCalendar	指定Cron表达式。精度取决于Cron表达式,也就是最大精度可以【到秒】
     * DailyCalendar	指定每天的时间段(rangeStartingTime,
     * rangeEndingTime),格式是HH:MM[:SS[:mmm]]。也就是最大精度可以【到毫秒】
     * HolidayCalendar	指定特定的日期,比如20140613。精度到【天】
     * MonthlyCalendar	指定每月的几号。可选值为1-31。精度是【天】
     * WeeklyCalendar	指定每星期的星期几,可选值比如为java.util.Calendar.SUNDAY。精度是【天】
     * modifiedByCalendar
     *  </pre></blockquote>
     *  <p>
     * @return
     */
    String  calendar() default "";

    /**
     * 触发器有效期
     * @return
     */
    TimeLimit timeLimit() default @TimeLimit;

    /**
     * 触发器JobDataMap<br/>
     * 创建JobDataMap在@Configuration中使用@Bean创建的对象名
     * @return
     */
    String dataMap() default "";

    /**
     * 错过调度策略机制<br/>
     * MISFIRE_INSTRUCTION_DO_NOTHING<br/>
     * <blockquote>
     *      不触发立即执行<br/>
     *      等待下次Cron触发频率到达时刻开始按照Cron频率依次执行<br/>
     *  </blockquote>
     * MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY<br/>
     * <blockquote>
     *      以错过的第一个频率时间立刻开始执行<br/>
     *      重做错过的所有频率周期后<br/>
     *      当下一次触发频率发生时间大于当前时间后,再按照正常的Cron频率依次执行<br/>
     * </blockquote>
     * MISFIRE_INSTRUCTION_FIRE_ONCE_NOW<br/>
     * <blockquote>
     *      以当前时间为触发频率立刻触发一次执行<br/>
     *      然后按照Cron频率依次执行<br/>
     * </blockquote>
     * @return
     */
    int misfire() default org.quartz.CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING;



}



import com.commnetsoft.annotation.group.TriggerDailyTimeIntervalGroup;
import org.quartz.DateBuilder;

import java.lang.annotation.*;
import java.util.Calendar;

/**
 * 每天时间段间隔触发器
 * 指定每天的某个时间段内,以一定的时间间隔执行任务。并且它可以支持指定星期。
 * <p>
 * 它适合的任务类似于:指定每天9:00 至 18:00 ,每隔50秒执行一次,并且只要周一至周五执行。
 *
 * @author Brack.zhu
 * @date 2020/6/23
 */
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(TriggerDailyTimeIntervalGroup.class)
public @interface TriggerDailyTimeInterval {

    /**
     * 触发器名称
     * @return
     */
    String name();

    /**
     * 每天任务开始时间<br/>
     *  格式:HH:mm:ss<br/>
     *   08:15:00
     * @return
     */
    String startTimeOfDay();

    /**
     * 每天任务结束时间<br/>
     *   格式:HH:mm:ss<br/>
     *    17:15:00
     * @return
     */
    String endTimeOfDay();

    /**
     * 一周内需要执行的星期几<br/>
     * {@link Calendar#MONDAY}
     * @return
     */
    int[] daysOfWeek();


    /**
     * 间隔时间
     * @return
     */
    int repeatInterval();

    /**
     * 间隔时间单位类型
     * @return
     */
    DateBuilder.IntervalUnit repeatIntervalUnit();

    /*--------------------------------以下非必填-------------------------------------------*/

    /**
     * 重复次数
     * 执行次数为原始执行一次 + 重复次数
     * @return
     */
    int repeatCount() default -1;

    /**
     * 触发器描述
     * @return
     */
    String description() default "";

    /**
     * 触发器包含、排除 日历<br/>
     * 详见
     * {@link TriggerCron#modifiedByCalendar()}
     *
     * @return
     */
    String modifiedByCalendar() default "";

    /**
     * 触发器有效期
     * @return
     */
    TimeLimit timeLimit() default @TimeLimit;

    /**
     * 触发器JobDataMap<br/>
     * 创建JobDataMap在@Configuration中使用@Bean创建的对象名
     * @return
     */
    String dataMap() default "";

    /**
     *  错过调度策略机制<br/>
     * MISFIRE_INSTRUCTION_DO_NOTHING<br/>
     * <blockquote>
     *      不触发等下次<br/>
     *  </blockquote>
     * MISFIRE_INSTRUCTION_FIRE_ONCE_NOW<br/>
     * <blockquote>
     *      立刻执行一次,然后就按照正常的计划执行。<br/>
     * </blockquote>
     * MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY<br/>
     * <blockquote>
     *      忽略所有的超时状态,按照触发器的策略执行。
     * </blockquote>
     *
     * @return
     */
    int misfire() default org.quartz.DailyTimeIntervalTrigger.MISFIRE_INSTRUCTION_DO_NOTHING;

}



import com.commnetsoft.annotation.group.TriggerSimpleGroup;

import java.lang.annotation.*;

/**
 * 简单的触发器<br/>
 * 以一定的时间间隔(单位是毫秒)执行的任务。
 *
 * @author Brack.zhu
 * @date 2020/6/23
 */
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(TriggerSimpleGroup.class)
public @interface TriggerSimple {

    /**
     * 触发器名称
     *
     * @return
     */
    String name();

    /**
     * 间隔时间,单位毫秒
     *
     * @return
     */
    long repeatInterval();

    /*--------------------------------以下非必填-------------------------------------------*/

    /**
     * 重复触发总次数
     * 执行次数为原始执行一次 + 重复触发总次数
     *
     * @return
     */
    int repeatCount() default -1;

    /**
     * 触发器描述
     *
     * @return
     */
    String description() default "";

    /**
     * 触发器包含、排除 日历<br/>
     * 详见
     * {@link TriggerCron#modifiedByCalendar()}
     *
     * @return
     */
    String modifiedByCalendar() default "";

    /**
     * 触发器有效期
     *
     * @return
     */
    TimeLimit timeLimit() default @TimeLimit;

    /**
     * 触发器JobDataMap<br/>
     * 创建JobDataMap在@Configuration中使用@Bean创建的对象名
     *
     * @return
     */
    String dataMap() default "";

    /**
     * 错过调度策略机制<br/>
     * MISFIRE_INSTRUCTION_FIRE_NOW<br/>
     * <blockquote>
     * 以当前时间为触发频率立即触发执行<br/>
     * 执行至FinalTIme的剩余周期次数<br/>
     * 以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算得到<br/>
     * 调整后的FinalTime会略大于根据starttime计算的到的FinalTime值<br/>
     * </blockquote>
     * MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY<br/>
     * <blockquote>
     * 以错过的第一个频率时间立刻开始执行<br/>
     * 重做错过的所有频率周期<br/>
     * 当下一次触发频率发生时间大于当前时间以后,按照Interval的依次执行剩下的频率<br/>
     * 共执行RepeatCount+1次<br/>
     * </blockquote>
     * MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT<br/>
     * <blockquote>
     * 不触发立即执行<br/>
     * 等待下次触发频率周期时刻,执行至FinalTime的剩余周期次数<br/>
     * 以startTime为基准计算周期频率,并得到FinalTime<br/>
     * 即使中间出现pause,resume以后保持FinalTime时间不变<br/>
     * </blockquote>
     * MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT<br/>
     * <blockquote>
     * 以当前时间为触发频率立即触发执行<br/>
     * 执行至FinalTIme的剩余周期次数<br/>
     * 以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算得到<br/>
     * 调整后的FinalTime会略大于根据starttime计算的到的FinalTime值<br/>
     * </blockquote>
     * MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT<br/>
     * <blockquote>
     * 不触发立即执行<br/>
     * 等待下次触发频率周期时刻,执行至FinalTime的剩余周期次数<br/>
     * 以startTime为基准计算周期频率,并得到FinalTime<br/>
     * 即使中间出现pause,resume以后保持FinalTime时间不变<br/>
     * </blockquote>
     * MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT<br/>
     * <blockquote>
     * 以当前时间为触发频率立即触发执行<br/>
     * 执行至FinalTIme的剩余周期次数<br/>
     * 以调度或恢复调度的时刻为基准的周期频率,FinalTime根据剩余次数和当前时间计算得到<br/>
     * 调整后的FinalTime会略大于根据starttime计算的到的FinalTime值<br/>
     * </blockquote>
     *
     * @return
     */
    int misfire() default org.quartz.SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW;


}

项目运行扫描入库并注册到调度器

java
/**
 * 项目启动扫描 @Task 注解 把定时任务刷到数据库
 *
 * @author luos
 * @date 2019/7/17
 */
@Component
public class TaskRunner implements CommandLineRunner {

    private Logger log = LoggerFactory.getLogger(TaskRunner.class);

    @Autowired
    private TaskInitService taskInitService;

    @Autowired
    private AmqpHelper amqpHelper;

    @Value("${spring.application.name}")
    private String applicationName;

    @Autowired
    private TaskService taskService;

    @Override
    public void run(String... args) throws Exception {
        //发送调度器name
        Object bean = SpringContextUtil.getBean("quartzProperties");
        Properties properties = (Properties) bean;
        //判断实例名是否手动设置
        String instanceName = properties.getProperty("org.quartz.scheduler.instanceName");
        if (StringUtils.isBlank(instanceName)) {
            properties.setProperty("org.quartz.scheduler.instanceName", applicationName);
        }
        amqpHelper.sendToExchange(QuartzEvents.QUARTZ_SCHEDULER_NAME, instanceName);

        List<String> taskList = new ArrayList<>();
        List<Class<? extends Job>> classes = ClassScaner.scan(CoreConstant.Package.BASE, Job.class);
        for (Class<? extends Job> clazz : classes) {
            JobTask task = AnnotationUtils.getAnnotation(clazz, JobTask.class);

            //获取扫描到任务类job名集合
            if (isEmpty(task)) {
                taskList.add(clazz.getName());
                log.warn("初始化定时任务失败,未找到@Task注解:class:{}", clazz);
                continue;
            } else {
                if (StringUtils.isNotBlank(task.name())) {
                    taskList.add(task.name());
                } else {
                    taskList.add(clazz.getName());
                }
            }

            //触发器各类型集合
            Set<TriggerCron> cronTriggerGroup = AnnotationUtils.getDeclaredRepeatableAnnotations(clazz, TriggerCron.class);
            Set<TriggerSimple> simpleTriggerGroup = AnnotationUtils.getDeclaredRepeatableAnnotations(clazz, TriggerSimple.class);
            Set<TriggerDailyTimeInterval> dailyTimeIntervalTriggerGroup = AnnotationUtils.getDeclaredRepeatableAnnotations(clazz, TriggerDailyTimeInterval.class);
            Set<TriggerCalendarInterval> calendarIntervalTriggerGroup = AnnotationUtils.getDeclaredRepeatableAnnotations(clazz, TriggerCalendarInterval.class);
            if (isEmpty(cronTriggerGroup) && isEmpty(simpleTriggerGroup) && isEmpty(dailyTimeIntervalTriggerGroup) && isEmpty(calendarIntervalTriggerGroup)) {
                log.warn("初始化定时任务失败,未找到相应的Trigger触发器注解:class:{}", clazz);
                continue;
            }
            try {
                taskInitService.initTask(clazz, task, cronTriggerGroup, simpleTriggerGroup, dailyTimeIntervalTriggerGroup, calendarIntervalTriggerGroup);
            } catch (Exception e) {
                log.error("初始化定时任务失败,class:{}", clazz, e);
                throw new Exception("初始化定时任务失败,class:" + clazz, e);
            }
        }
        //删除 调度器中不存在任务类的注册任务
        List<JobKey> jobKeys = taskService.JobKeys();
        for (JobKey jobKey : jobKeys) {
            if (!taskList.contains(jobKey.getName())) {
                taskService.delJob(jobKey.getName(), jobKey.getGroup());
            }
        }
    }

    /**
     * 判断注解是否为空
     *
     * @param annotation
     * @return
     */
    public boolean isEmpty(Annotation annotation) {
        if (null != annotation) {
            return false;
        }
        return true;
    }

    /**
     * 是否空注解集合
     *
     * @param annotations
     * @return
     */
    public boolean isEmpty(Set<? extends Annotation> annotations) {
        if (CollectionUtils.isEmpty(annotations)) {
            return true;
        }
        return false;
    }

}
存入数据库
java
import com.alibaba.fastjson.JSON;
import com.commnetsoft.QrtzError;
import com.commnetsoft.annotation.*;
import com.commnetsoft.commons.utils.StringUtils;
import com.commnetsoft.core.utils.SpringContextUtil;
import com.commnetsoft.dao.QrtzSimpleExistDao;
import com.commnetsoft.dao.QrtzTriggerDefaultDao;
import com.commnetsoft.exception.MicroRuntimeException;
import com.commnetsoft.model.QrtzSimpleExistPo;
import com.commnetsoft.model.QrtzTriggerDefaultPo;
import com.commnetsoft.service.builder.CronTriggerBuilder;
import com.commnetsoft.service.builder.StandardJobBuilder;
import org.apache.commons.collections.CollectionUtils;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * 任务初始化服务
 *
 * @author Brack.zhu
 * @date 2020/6/24
 */
@Service
public class TaskInitService {

    private Logger log = LoggerFactory.getLogger(TaskInitService.class);

    @Autowired
    private CronTriggerBuilder cronTriggerBuilder;

    @Autowired
    private StandardJobBuilder standardJobBuilder;

    @Autowired
    private TaskService taskService;

    @Autowired
    private QrtzTriggerDefaultDao qrtzTriggerDefaultDao;

    @Autowired
    private QrtzSimpleExistDao qrtzSimpleExistDao;

    @Value("${spring.application.name}")
    private String applicationName;

    /**
     * 初始化任务
     *
     * @param jobClazz                      任务类
     * @param task                          任务注解
     * @param cronTriggerGroup              cron触发器集合
     * @param simpleTriggerGroup            简单间隔触发器集合
     * @param dailyTimeIntervalTriggerGroup 每天时间间隔触发器集合
     * @param calendarIntervalTriggerGroup  日历间隔触发器集合
     * @throws MicroRuntimeException
     */
    public void initTask(Class<? extends Job> jobClazz, JobTask task,
                         Set<TriggerCron> cronTriggerGroup,
                         Set<TriggerSimple> simpleTriggerGroup,
                         Set<TriggerDailyTimeInterval> dailyTimeIntervalTriggerGroup,
                         Set<TriggerCalendarInterval> calendarIntervalTriggerGroup) throws MicroRuntimeException, SchedulerException {
        //必须都构建成功
        JobDetail jobDetail = standardJobBuilder.build(jobClazz, task);
        Set<CronTrigger> cronTriggers = cronTriggerBuilder.build(jobDetail, cronTriggerGroup);
        Set<SimpleTrigger> simpleTriggers = cronTriggerBuilder.buildSimple(jobDetail, simpleTriggerGroup);
        Set<DailyTimeIntervalTrigger> dailyTimeIntervalTriggers = cronTriggerBuilder.buildDailyTimeInterval(jobDetail, dailyTimeIntervalTriggerGroup);
        Set<CalendarIntervalTrigger> calendarIntervalTriggers = cronTriggerBuilder.buildCalendarInterval(jobDetail, calendarIntervalTriggerGroup);
        //TODO 其他触发器类型
        //以上构建都成功后进入创建流程,减少不必要的脏数据
        if (!cronTriggers.isEmpty()) {
            initTaskCron(jobDetail, cronTriggers);
        }
        if (!simpleTriggers.isEmpty()) {
            initTaskSimple(jobDetail, simpleTriggers);
        }

        if (!dailyTimeIntervalTriggers.isEmpty()) {
            initTaskDailyTime(jobDetail, dailyTimeIntervalTriggers);
        }

        if (!calendarIntervalTriggers.isEmpty()) {
            initTaskCalendar(jobDetail, calendarIntervalTriggers);
        }
    }

    public void initTaskCron(JobDetail job, Set<CronTrigger> cronTriggers) throws MicroRuntimeException, SchedulerException {

        if (null == job || null == cronTriggers) {
            throw new MicroRuntimeException(QrtzError.args_valid_failed);
        }
        String jobname = job.getKey().getName();
        String jobgroup = job.getKey().getGroup();

        //获取调度器中所有cron 触发器
        List<? extends Trigger> triggers = taskService.getJobTrigger(jobname, jobgroup);
        List<CronTrigger> cronTriggerList = new ArrayList<>();
        for (Trigger trigger : triggers) {
            if (trigger instanceof CronTrigger) {
                CronTrigger cronTrigger = (CronTrigger) trigger;
                cronTriggerList.add(cronTrigger);
            }
        }
        //调度器中的触发器 在代码中没有 并且数据库中没有默认值(未被运维手动修改过)  删除该触发器
        if (CollectionUtils.isNotEmpty(cronTriggerList)) {
            for (CronTrigger cronTrigger : cronTriggerList) {
                TriggerKey key1 = cronTrigger.getKey();
                boolean isDef = isDefault(jobname, jobgroup, cronTrigger.getKey().getName(), cronTrigger.getKey().getGroup());
                boolean equals = true;
                for (CronTrigger t : cronTriggers) {
                    TriggerKey key2 = t.getKey();
                    if (key1.equals(key2)) {
                        equals = false;
                    }
                }
                if (equals && !isDef) {
                    taskService.delTigger(key1.getName(), key1.getGroup());
                }
            }
        }

        for (CronTrigger cronTrigger : cronTriggers) {
            initTaskCron(job, cronTrigger);
        }

    }

    public void initTaskCron(JobDetail job, CronTrigger cronTrigger) throws MicroRuntimeException, SchedulerException {
        //任务名称 .任务分组
        JobKey jobKey = job.getKey();
        //判断实例名是否手动设置,获取实例名
        String instanceName = geInstanceName();
        String jobname = jobKey.getName();
        String jobgroup = jobKey.getGroup();
        //触发器 名称 分组 触发器数据(json)
        TriggerKey triggerKey = cronTrigger.getKey();
        String tigname = triggerKey.getName();
        String tiggroup = triggerKey.getGroup();

        //判断是否默认值
        boolean isDef = isDefault(jobname, jobgroup, tigname, tiggroup);
        if (isDef) {
            QrtzTriggerDefaultPo qrtzTriggerDefaultPo = new QrtzTriggerDefaultPo();
            qrtzTriggerDefaultPo.setJobname(jobname);
            qrtzTriggerDefaultPo.setJobgroup(jobgroup);
            qrtzTriggerDefaultPo.setTriggername(tigname);
            qrtzTriggerDefaultPo.setTriggergroup(tiggroup);
            QrtzTriggerDefaultPo qd = qrtzTriggerDefaultDao.selectOne(qrtzTriggerDefaultPo);
            //默认值库里有数据 更新代码值 到默认值库
            qd.setSchedname(instanceName);
            qd.setTriggerdata(JSON.toJSONString(cronTrigger));
            qd.setTriggertype(QrtzTriggerDefaultPo.tigger_cron);
            qd.setCreatetime(new Date());
            qrtzTriggerDefaultDao.updateByPrimaryKeySelective(qd);
        } else {
            //获取调度器中的触发器
            Trigger schedulerTrigger = taskService.getSingleTrigger(tigname, tiggroup);

            boolean update = cronTriggerBuilder.cronIsUpdate(cronTrigger, (CronTrigger) schedulerTrigger);
            if (!update) {
                if (taskService.checkJobExists(jobKey)) {
                    //任务存在 修改或新增 Trigger
                    taskService.modifyTrigger(job, cronTrigger);
                } else {
                    //任务不存在 注册job和Trigger到调度器中
                    taskService.addNewJob(job, cronTrigger);
                }
            }
        }
    }


    public void initTaskSimple(JobDetail job, Set<SimpleTrigger> simpleTriggers) throws MicroRuntimeException, SchedulerException {
        //TODO
        if (null == job || null == simpleTriggers) {
            throw new MicroRuntimeException(QrtzError.args_valid_failed);
        }
        for (SimpleTrigger simpleTrigger : simpleTriggers) {

            boolean isexsit = isexsit(job, simpleTrigger);
            if (!isexsit) {
                initTaskSimple(job, simpleTrigger);
                //初始化后的simpletrigger组名 保存到库 ,作记录
                advance(job, simpleTrigger);
            }
        }
    }


    public void initTaskSimple(JobDetail job, SimpleTrigger simpleTrigger) throws MicroRuntimeException, SchedulerException {
        //任务名称 .任务分组
        JobKey jobKey = job.getKey();
        if (taskService.checkJobExists(jobKey)) {
            //任务存在 修改或新增 Trigger
            taskService.modifyTrigger(job, simpleTrigger);
        } else {
            //任务不存在 注册job和Trigger到调度器中
            taskService.addNewJob(job, simpleTrigger);
        }
    }

    public void initTaskCalendar(JobDetail job, Set<CalendarIntervalTrigger> calendarIntervalTriggers) throws MicroRuntimeException, SchedulerException {
        if (null == job || null == calendarIntervalTriggers) {
            throw new MicroRuntimeException(QrtzError.args_valid_failed);
        }
        for (CalendarIntervalTrigger calendarIntervalTrigger : calendarIntervalTriggers) {
            boolean isexsit = isexsit(job, calendarIntervalTrigger);
            if (!isexsit) {
                initTaskCalendar(job, calendarIntervalTrigger);
                //初始化后的simpletrigger组名 保存到库 ,作记录
                advance(job, calendarIntervalTrigger);
            }
        }

    }

    public void initTaskCalendar(JobDetail job, CalendarIntervalTrigger calendarIntervalTrigger) throws MicroRuntimeException, SchedulerException {
        //任务名称 .任务分组
        JobKey jobKey = job.getKey();

        //获取调度器中的触发器
        if (taskService.checkJobExists(jobKey)) {
            //任务存在 修改或新增 Trigger
            taskService.modifyTrigger(job, calendarIntervalTrigger);
        } else {
            //任务不存在 注册job和Trigger到调度器中
            taskService.addNewJob(job, calendarIntervalTrigger);
        }
    }


    public void initTaskDailyTime(JobDetail job, Set<DailyTimeIntervalTrigger> dailyTimeIntervalTriggers) throws MicroRuntimeException, SchedulerException {
        if (null == job || null == dailyTimeIntervalTriggers) {
            throw new MicroRuntimeException(QrtzError.args_valid_failed);
        }
        for (DailyTimeIntervalTrigger dailyTimeIntervalTrigger : dailyTimeIntervalTriggers) {
            boolean isexsit = isexsit(job, dailyTimeIntervalTrigger);
            if (!isexsit) {
                initTaskDailyTime(job, dailyTimeIntervalTrigger);
                //初始化后的simpletrigger组名 保存到库 ,作记录
                advance(job, dailyTimeIntervalTrigger);
            }
        }

    }

    public void initTaskDailyTime(JobDetail job, DailyTimeIntervalTrigger dailyTimeIntervalTriggers) throws MicroRuntimeException, SchedulerException {
        //任务名称 .任务分组
        JobKey jobKey = job.getKey();
        if (taskService.checkJobExists(jobKey)) {
            //任务存在 修改或新增 Trigger
            taskService.modifyTrigger(job, dailyTimeIntervalTriggers);
        } else {
            //任务不存在 注册job和Trigger到调度器中
            taskService.addNewJob(job, dailyTimeIntervalTriggers);
        }
    }


    /**
     * 获取 调度器实例名
     *
     * @return
     */
    private String geInstanceName() {
        Object bean = SpringContextUtil.getBean("quartzProperties");
        Properties properties = (Properties) bean;
        //判断实例名是否手动设置
        String instanceName = properties.getProperty("org.quartz.scheduler.instanceName");
        if (StringUtils.isBlank(instanceName)) {
            instanceName = applicationName;
        }
        return instanceName;
    }

    /**
     * 触发器默认值库里面是否 有数据   true : 有数据  false : 无数据
     *
     * @param jobname
     * @param jobgroup
     * @param triggername
     * @return
     */

    public boolean isDefault(String jobname, String jobgroup, String triggername, String triggergroup) {
        boolean isDef = false;
        QrtzTriggerDefaultPo qrtzTriggerDefaultPo = new QrtzTriggerDefaultPo();
        qrtzTriggerDefaultPo.setJobname(jobname);
        qrtzTriggerDefaultPo.setJobgroup(jobgroup);
        qrtzTriggerDefaultPo.setTriggername(triggername);
        qrtzTriggerDefaultPo.setTriggergroup(triggergroup);
        List<QrtzTriggerDefaultPo> list = qrtzTriggerDefaultDao.select(qrtzTriggerDefaultPo);
        if (CollectionUtils.isNotEmpty(list)) {
            isDef = true;
        }
        return isDef;
    }

    /**
     * trigger 是否已经初始化过,到库里面了
     *
     * @param job
     * @param trigger
     * @return
     */
    private boolean isexsit(JobDetail job, Trigger trigger) {
        boolean exsit = true;
        String schedname = geInstanceName();
        QrtzSimpleExistPo qrtzSimpleExistPo = new QrtzSimpleExistPo();
        qrtzSimpleExistPo.setJobname(job.getKey().getName());
        qrtzSimpleExistPo.setJobgroup(job.getKey().getGroup());
        qrtzSimpleExistPo.setTriggername(trigger.getKey().getName());
        qrtzSimpleExistPo.setTriggergroup(trigger.getKey().getGroup());
        qrtzSimpleExistPo.setSchedname(schedname);
        List<QrtzSimpleExistPo> list = qrtzSimpleExistDao.select(qrtzSimpleExistPo);
        if (CollectionUtils.isEmpty(list)) {
            exsit = false;
        }
        return exsit;
    }

    /**
     * 初始化后的simpletrigger组名 保存到库 ,作记录
     *
     * @param job
     * @param trigger
     * @return
     */
    private void advance(JobDetail job, Trigger trigger) {
        String schedname = geInstanceName();
        QrtzSimpleExistPo qrtzSimpleExistPo = new QrtzSimpleExistPo();
        qrtzSimpleExistPo.setSchedname(schedname);
        qrtzSimpleExistPo.setJobname(job.getKey().getName());
        qrtzSimpleExistPo.setJobgroup(job.getKey().getGroup());
        qrtzSimpleExistPo.setTriggername(trigger.getKey().getName());
        qrtzSimpleExistPo.setTriggergroup(trigger.getKey().getGroup());
        qrtzSimpleExistPo.setCreatetime(new Date());
        qrtzSimpleExistDao.insertSelective(qrtzSimpleExistPo);
    }

}
构建接口
java
import com.commnetsoft.commons.utils.BeanUtils;
import com.commnetsoft.commons.utils.StringUtils;
import com.commnetsoft.core.utils.SpringContextUtil;
import org.quartz.JobDataMap;

import java.util.Map;

/**
 * @author Brack.zhu
 * @date 2020/6/28
 */
public interface IBuilder {

    /**
     * 构建JobDataMap对象
     * @param pojoName
     * @return
     * @throws Exception
     */
    default JobDataMap buildJobDataMap(String pojoName) throws Exception {
        if (StringUtils.isNotEmpty(pojoName)) {
            Object bean = SpringContextUtil.getBean(pojoName);
            Map<String, Object> objectMap = BeanUtils.toMap(bean);
            return new JobDataMap(objectMap);
        }
        return null;
    }


}
构建jobdetail
java
import com.commnetsoft.annotation.JobTask;
import com.commnetsoft.exception.MicroRuntimeException;
import org.quartz.Job;
import org.quartz.JobDetail;

/**
 * @author Brack.zhu
 * @date 2020/6/28
 */
public interface IJobBuilder extends IBuilder {

    JobDetail build(Class<? extends Job> jobClazz, JobTask task) throws MicroRuntimeException;

    /**
     * 获取默认任务名称
     * @param jobClazz
     * @return
     */
    default String getDefName(Class<? extends Job> jobClazz) {
        return jobClazz.getName();
    }

    /**
     * 获取默认任务分组
     * @param jobClazz
     * @return
     */
    default String getDefGroup(Class<? extends Job> jobClazz) {
        return jobClazz.getPackage().getName();
    }
}
java
import com.commnetsoft.QrtzError;
import com.commnetsoft.annotation.JobTask;
import com.commnetsoft.commons.utils.StringUtils;
import com.commnetsoft.exception.MicroRuntimeException;
import org.quartz.*;
import org.springframework.stereotype.Component;

/**
 * 标准任务构建器
 * @author Brack.zhu
 * @date 2020/6/28
 */
@Component
public class StandardJobBuilder implements IJobBuilder {

    @Override
    public JobDetail build(Class<? extends Job> jobClazz, JobTask task) throws MicroRuntimeException {
        if (null == jobClazz || null == task) {
            throw new MicroRuntimeException(QrtzError.args_valid_failed);
        }
        try {
            JobKey jobKey = JobKey.jobKey(getJobName(jobClazz, task), getJobGroup(jobClazz,task));
            JobBuilder jobBuilder = JobBuilder.newJob(jobClazz).withIdentity(jobKey).withDescription(task.desc());
            JobDataMap jobDataMap = buildJobDataMap(task.dataMap());
            if(null!=jobDataMap){
                jobBuilder.setJobData(jobDataMap);
            }
            return jobBuilder.storeDurably().build();
        } catch (Exception e) {
            throw new MicroRuntimeException(QrtzError.jon_create_failed,e);
        }
    }

    /**
     * 获取任务名称,空取类名
     * @param jobClazz
     * @param task
     * @return
     */
    public  String getJobName(Class<? extends Job> jobClazz,JobTask task){
        String name=task.name();
        if(StringUtils.isBlank(name)){
           name=getDefName(jobClazz);
        }
        return name;
    }

    /**
     * 获取任务分组,为空使用包路径
     * @param jobClazz
     * @param task
     * @return
     */
    public  String getJobGroup(Class<? extends Job> jobClazz,JobTask task){
        String group=task.group();
        if(StringUtils.isBlank(group)){
            group=getDefGroup(jobClazz);
        }
        return group;
    }

}
构建触发器
java
import com.commnetsoft.annotation.*;
import com.commnetsoft.exception.MicroRuntimeException;
import org.quartz.JobDetail;
import org.quartz.Trigger;

import java.util.Date;

/**
 * @author Brack.zhu
 * @date 2020/6/24
 */
public interface ITriggerBuilder extends IBuilder {

    <T extends Trigger> T build(JobDetail jobDetail, TriggerCron cronTrigger) throws MicroRuntimeException;

    <T extends Trigger> T build(JobDetail jobDetail, TriggerSimple simpleTrigger) throws MicroRuntimeException;

    <T extends Trigger> T build(JobDetail jobDetail, TriggerDailyTimeInterval cronTrigger) throws MicroRuntimeException;

    <T extends Trigger> T build(JobDetail jobDetail, TriggerCalendarInterval cronTrigger) throws MicroRuntimeException;

    default Date getStart(TimeLimit timeLimit) {
        if (timeLimit.start() < 0) {
            return new Date();
        }
        return new Date(timeLimit.start());
    }

    default Date getEnd(TimeLimit timeLimit) {
        return new Date(timeLimit.end());
    }

    /**
     * 构建完整(入库)的触发器名称
     *
     * @param jobDetail
     * @param triggerName
     * @return
     */
    default String buildRealName(JobDetail jobDetail, String triggerName) {
        String className = jobDetail.getJobClass().getName();
        return className + "#" + triggerName;
    }
}
java
import com.commnetsoft.QrtzError;
import com.commnetsoft.annotation.TriggerCalendarInterval;
import com.commnetsoft.annotation.TriggerCron;
import com.commnetsoft.annotation.TriggerDailyTimeInterval;
import com.commnetsoft.annotation.TriggerSimple;
import com.commnetsoft.commons.utils.StringUtils;
import com.commnetsoft.exception.MicroRuntimeException;
import org.quartz.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * @author Brack.zhu
 * @date 2020/6/24
 */
@Component
public class CronTriggerBuilder implements ITriggerBuilder {

    public <T extends Trigger> Set<T> build(JobDetail jobDetail, Set<TriggerCron> triggerCronGroup) throws MicroRuntimeException {
        if (null == jobDetail || null == triggerCronGroup) {
            throw new MicroRuntimeException(QrtzError.args_valid_failed);
        }
        Set<T> triggers = new HashSet<>();
        for (TriggerCron cronTrigger : triggerCronGroup) {
            CronTrigger trigger = build(jobDetail, cronTrigger);
            triggers.add((T) trigger);
        }
        return triggers;
    }

    @Override
    public CronTrigger build(JobDetail jobDetail, TriggerCron cronTrigger) throws MicroRuntimeException {
        if (null == jobDetail || null == cronTrigger) {
            throw new MicroRuntimeException(QrtzError.args_valid_failed);
        }
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(getName(jobDetail, cronTrigger), jobDetail.getKey().getGroup());
            CronScheduleBuilder schedBuilder = CronScheduleBuilder.cronSchedule(cronTrigger.cron());
            int misfire = cronTrigger.misfire();
            // 设置任务misfire后 补偿执行策略
            schedBuilder = setCronStrategy(misfire, schedBuilder);


            TriggerBuilder triggerBuilder = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(schedBuilder)
                    .startAt(getStart(cronTrigger.timeLimit())).endAt(getEnd(cronTrigger.timeLimit())).withDescription(cronTrigger.desc());
            JobDataMap jobDataMap = buildJobDataMap(cronTrigger.dataMap());
            if (null != jobDataMap) {
                triggerBuilder.usingJobData(jobDataMap);
            }
            //触发器包含、排除 日历
            String modifiedByCalendar = cronTrigger.calendar();
            if (StringUtils.isNotEmpty(modifiedByCalendar)) {
                triggerBuilder.modifiedByCalendar(modifiedByCalendar);
            }
            return (CronTrigger) triggerBuilder.forJob(jobDetail.getKey()).build();
        } catch (Exception e) {
            throw new MicroRuntimeException(QrtzError.trigger_create_failed, e);
        }
    }

    /**
     * cron 根据自定义传入参数 设置任务misfire后 补偿执行策略
     *
     * @param misfire
     * @param schedBuilder
     * @return
     */
    public CronScheduleBuilder setCronStrategy(int misfire, CronScheduleBuilder schedBuilder) {
        if (misfire == CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING) {
            schedBuilder.withMisfireHandlingInstructionDoNothing();
        } else if (misfire == CronTrigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY) {
            schedBuilder.withMisfireHandlingInstructionIgnoreMisfires();
        } else if (misfire == CronTrigger.MISFIRE_INSTRUCTION_FIRE_ONCE_NOW) {
            schedBuilder.withMisfireHandlingInstructionFireAndProceed();
        }
        return schedBuilder;
    }

    /**
     * simple 根据自定义传入参数 设置任务misfire后 补偿执行策略
     *
     * @param misfire
     * @param schedBuilder
     * @return
     */
    public SimpleScheduleBuilder setSimpleStrategy(int misfire, SimpleScheduleBuilder schedBuilder) {
        if (misfire == SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW) {
            schedBuilder.withMisfireHandlingInstructionFireNow();
        } else if (misfire == SimpleTrigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY) {
            schedBuilder.withMisfireHandlingInstructionIgnoreMisfires();
        } else if (misfire == SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT) {
            schedBuilder.withMisfireHandlingInstructionNextWithExistingCount();
        } else if (misfire == SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT) {
            schedBuilder.withMisfireHandlingInstructionNowWithExistingCount();
        } else if (misfire == SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT) {
            schedBuilder.withMisfireHandlingInstructionNextWithRemainingCount();
        } else if (misfire == SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT) {
            schedBuilder.withMisfireHandlingInstructionNowWithRemainingCount();
        }
        return schedBuilder;
    }


    /**
     * DailyTimeInterval 根据自定义传入参数 设置任务misfire后 补偿执行策略
     *
     * @param misfire
     * @param schedBuilder
     * @return
     */
    public DailyTimeIntervalScheduleBuilder setDailyTimeIntervalStrategy(int misfire, DailyTimeIntervalScheduleBuilder schedBuilder) {
        if (misfire == DailyTimeIntervalTrigger.MISFIRE_INSTRUCTION_DO_NOTHING) {
            schedBuilder.withMisfireHandlingInstructionDoNothing();
        } else if (misfire == DailyTimeIntervalTrigger.MISFIRE_INSTRUCTION_FIRE_ONCE_NOW) {
            schedBuilder.withMisfireHandlingInstructionFireAndProceed();
        } else if (misfire == DailyTimeIntervalTrigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY) {
            schedBuilder.withMisfireHandlingInstructionIgnoreMisfires();
        }
        return schedBuilder;
    }

    /**
     * simple 根据自定义传入参数 设置任务misfire后 补偿执行策略
     *
     * @param misfire
     * @param schedBuilder
     * @return
     */
    public CalendarIntervalScheduleBuilder setCalendarIntervalStrategy(int misfire, CalendarIntervalScheduleBuilder schedBuilder) {
        if (misfire == CalendarIntervalTrigger.MISFIRE_INSTRUCTION_DO_NOTHING) {
            schedBuilder.withMisfireHandlingInstructionDoNothing();
        } else if (misfire == CalendarIntervalTrigger.MISFIRE_INSTRUCTION_FIRE_ONCE_NOW) {
            schedBuilder.withMisfireHandlingInstructionFireAndProceed();
        } else if (misfire == CalendarIntervalTrigger.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY) {
            schedBuilder.withMisfireHandlingInstructionIgnoreMisfires();
        }
        return schedBuilder;
    }

    /**
     * 判断 调度器中cron触发器 与 代码中的cron触发器 是否一致   true :一致   false :不一致
     *
     * @param trigger1
     * @param trigger2
     * @return
     */

    public boolean cronIsUpdate(CronTrigger trigger1, CronTrigger trigger2) {
        boolean isDef = true;
        if (null == trigger1 || null == trigger2) {
            return false;
        }
        //key
        if (!trigger1.equals(trigger2)) {
            isDef = false;
        }
        //表达式
        if (!trigger1.getCronExpression().equals(trigger2.getCronExpression())) {
            isDef = false;
        }
        //描述
        if (!trigger1.getDescription().equals(trigger2.getDescription())) {
            isDef = false;
        }
        //补偿策略
        if (!(trigger1.getMisfireInstruction() == trigger2.getMisfireInstruction())) {
            isDef = false;
        }
        return isDef;
    }


    /**
     * 判断 调度器中cron触发器 与 代码中的cron触发器 是否一致   true :一致   false :不一致
     *
     * @param trigger1
     * @param trigger2
     * @return
     */

    public boolean simpleIsUpdate(SimpleTrigger trigger1, SimpleTrigger trigger2) {
        boolean isDef = true;
        if (null == trigger1 || null == trigger2) {
            return false;
        }
        //key
        if (!trigger1.equals(trigger2)) {
            isDef = false;
        }
        //表达式
        if (!(trigger1.getRepeatCount() == (trigger2.getRepeatCount()))) {
            isDef = false;
        }

        //表达式
        if (!(trigger1.getRepeatInterval() == (trigger2.getRepeatInterval()))) {
            isDef = false;
        }
        //描述
        if (!trigger1.getDescription().equals(trigger2.getDescription())) {
            isDef = false;
        }
        //补偿策略
        if (!(trigger1.getMisfireInstruction() == trigger2.getMisfireInstruction())) {
            isDef = false;
        }
        return isDef;
    }

    /**
     * 获取触发器名称,使用类名加触发器名称唯一
     *
     * @return
     */
    public String getName(JobDetail jobDetail, TriggerCron cronTrigger) {
        String name = cronTrigger.name();
        return buildRealName(jobDetail, name);
    }

    /**
     * 简单触发器的构建
     *
     * @return
     */
    public <T extends Trigger> Set<T> buildSimple(JobDetail jobDetail, Set<TriggerSimple> triggerSimpleGroup) throws MicroRuntimeException {
        if (null == jobDetail || null == triggerSimpleGroup) {
            throw new MicroRuntimeException(QrtzError.args_valid_failed);
        }
        Set<T> triggers = new HashSet<>();
        for (TriggerSimple simpleTrigger : triggerSimpleGroup) {
            SimpleTrigger trigger = build(jobDetail, simpleTrigger);
            triggers.add((T) trigger);
        }
        return triggers;
    }

    /**
     * 简单触发器的构建
     *
     * @return
     */
    @Override
    public SimpleTrigger build(JobDetail jobDetail, TriggerSimple simpleTrigger) throws MicroRuntimeException {

        if (null == jobDetail || null == simpleTrigger) {
            throw new MicroRuntimeException(QrtzError.args_valid_failed);
        }

        TriggerBuilder simpleTriggerBuilder = null;
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(getName(jobDetail, simpleTrigger), jobDetail.getKey().getGroup());
            SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
                    .withIntervalInMilliseconds(simpleTrigger.repeatInterval());
            if (simpleTrigger.repeatCount() > -1) {
                simpleScheduleBuilder.withRepeatCount(simpleTrigger.repeatCount());
            }
            int misfire = simpleTrigger.misfire();

            // 设置任务misfire后 补偿执行策略
            simpleScheduleBuilder = setSimpleStrategy(misfire, simpleScheduleBuilder);

            simpleTriggerBuilder = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(simpleScheduleBuilder)
                    .startAt(getStart(simpleTrigger.timeLimit()))
                    .endAt(getEnd(simpleTrigger.timeLimit()))
                    .withDescription(simpleTrigger.description());
            JobDataMap jobDataMap = buildJobDataMap(simpleTrigger.dataMap());
            if (null != jobDataMap) {
                simpleTriggerBuilder.usingJobData(jobDataMap);
            }
            //触发器包含、排除 日历
            String modifiedByCalendar = simpleTrigger.modifiedByCalendar();
            if (StringUtils.isNotEmpty(modifiedByCalendar)) {
                simpleTriggerBuilder.modifiedByCalendar(modifiedByCalendar);
            }
            return (SimpleTrigger) simpleTriggerBuilder.forJob(jobDetail.getKey()).build();

        } catch (Exception e) {
            throw new MicroRuntimeException(QrtzError.trigger_create_failed, e);
        }

    }

    /**
     * 获取触发器名称,使用类名加触发器名称唯一
     *
     * @return
     */
    public String getName(JobDetail jobDetail, TriggerSimple simpleTrigger) {
        String name = simpleTrigger.name();
        return buildRealName(jobDetail, name);
    }


    /**
     * 日期触发器的构建
     *
     * @return
     */
    public <T extends Trigger> Set<T> buildDailyTimeInterval(JobDetail jobDetail, Set<TriggerDailyTimeInterval> TriggerDailyTimeIntervalGroup) throws MicroRuntimeException {
        if (null == jobDetail || null == TriggerDailyTimeIntervalGroup) {
            throw new MicroRuntimeException(QrtzError.args_valid_failed);
        }
        Set<T> triggers = new HashSet<>();
        for (TriggerDailyTimeInterval triggerDailyTimeInterval : TriggerDailyTimeIntervalGroup) {
            DailyTimeIntervalTrigger trigger = build(jobDetail, triggerDailyTimeInterval);
            triggers.add((T) trigger);
        }
        return triggers;
    }

    /**
     * 日期触发器的构建
     *
     * @return
     */
    @Override
    public DailyTimeIntervalTrigger build(JobDetail jobDetail, TriggerDailyTimeInterval triggerDailyTimeInterval) throws MicroRuntimeException {

        if (null == jobDetail || null == triggerDailyTimeInterval) {
            throw new MicroRuntimeException(QrtzError.args_valid_failed);
        }

        TriggerBuilder triggerBuilder = null;
        try {
            String[] start = triggerDailyTimeInterval.startTimeOfDay().split(":");
            String[] end = triggerDailyTimeInterval.endTimeOfDay().split(":");
            int[] week = triggerDailyTimeInterval.daysOfWeek();
            //先将int数组转换为数值流
            IntStream stream = Arrays.stream(week);
            Stream<Integer> integerStream = stream.boxed();
            Integer[] days = integerStream.toArray(Integer[]::new);

            TriggerKey triggerKey = TriggerKey.triggerKey(getName(jobDetail, triggerDailyTimeInterval), jobDetail.getKey().getGroup());
            DailyTimeIntervalScheduleBuilder dailyTimeIntervalScheduleBuilder = DailyTimeIntervalScheduleBuilder.dailyTimeIntervalSchedule()
                    .withInterval(triggerDailyTimeInterval.repeatInterval(), triggerDailyTimeInterval.repeatIntervalUnit())
                    .startingDailyAt(new TimeOfDay(Integer.parseInt(start[0]), Integer.parseInt(start[1]), Integer.parseInt(start[2])))
                    .endingDailyAt(new TimeOfDay(Integer.parseInt(end[0]), Integer.parseInt(end[1]), Integer.parseInt(end[2])))
                    .onDaysOfTheWeek(days);
            if (triggerDailyTimeInterval.repeatCount() > -1) {
                dailyTimeIntervalScheduleBuilder.withRepeatCount(triggerDailyTimeInterval.repeatCount());
            }
            int misfire = triggerDailyTimeInterval.misfire();

            // 设置任务misfire后 补偿执行策略
            dailyTimeIntervalScheduleBuilder = setDailyTimeIntervalStrategy(misfire, dailyTimeIntervalScheduleBuilder);

            triggerBuilder = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(dailyTimeIntervalScheduleBuilder)
                    .startAt(getStart(triggerDailyTimeInterval.timeLimit()))
                    .endAt(getEnd(triggerDailyTimeInterval.timeLimit()))
                    .withDescription(triggerDailyTimeInterval.description());

            JobDataMap jobDataMap = buildJobDataMap(triggerDailyTimeInterval.dataMap());
            if (null != jobDataMap) {
                triggerBuilder.usingJobData(jobDataMap);
            }
            //触发器包含、排除 日历
            String modifiedByCalendar = triggerDailyTimeInterval.modifiedByCalendar();
            if (StringUtils.isNotEmpty(modifiedByCalendar)) {
                triggerBuilder.modifiedByCalendar(modifiedByCalendar);
            }
            return (DailyTimeIntervalTrigger) triggerBuilder.forJob(jobDetail.getKey()).build();

        } catch (Exception e) {
            throw new MicroRuntimeException(QrtzError.trigger_create_failed, e);
        }

    }

    /**
     * 获取触发器名称,使用类名加触发器名称唯一
     *
     * @return
     */
    public String getName(JobDetail jobDetail, TriggerDailyTimeInterval triggerDailyTimeInterval) {
        String name = triggerDailyTimeInterval.name();
        return buildRealName(jobDetail, name);
    }


    /**
     * 日历触发器的构建
     *
     * @return
     */
    public <T extends Trigger> Set<T> buildCalendarInterval(JobDetail jobDetail, Set<TriggerCalendarInterval> triggerCalendarIntervals) throws MicroRuntimeException {
        if (null == jobDetail || null == triggerCalendarIntervals) {
            throw new MicroRuntimeException(QrtzError.args_valid_failed);
        }
        Set<T> triggers = new HashSet<>();
        for (TriggerCalendarInterval triggerDailyTimeInterval : triggerCalendarIntervals) {
            CalendarIntervalTrigger trigger = build(jobDetail, triggerDailyTimeInterval);
            triggers.add((T) trigger);
        }
        return triggers;
    }

    /**
     * 日历触发器的构建
     *
     * @return
     */
    @Override
    public CalendarIntervalTrigger build(JobDetail jobDetail, TriggerCalendarInterval triggerCalendarInterval) throws MicroRuntimeException {

        if (null == jobDetail || null == triggerCalendarInterval) {
            throw new MicroRuntimeException(QrtzError.args_valid_failed);
        }

        TriggerBuilder simpleTriggerBuilder = null;
        try {

            TriggerKey triggerKey = TriggerKey.triggerKey(getName(jobDetail, triggerCalendarInterval), jobDetail.getKey().getGroup());
            CalendarIntervalScheduleBuilder calendarIntervalScheduleBuilder = CalendarIntervalScheduleBuilder.calendarIntervalSchedule()
                    .withInterval(triggerCalendarInterval.repeatInterval(), triggerCalendarInterval.repeatIntervalUnit());
            int misfire = triggerCalendarInterval.misfire();

            // 设置任务misfire后 补偿执行策略
            calendarIntervalScheduleBuilder = setCalendarIntervalStrategy(misfire, calendarIntervalScheduleBuilder);

            simpleTriggerBuilder = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(calendarIntervalScheduleBuilder)
                    .startAt(getStart(triggerCalendarInterval.timeLimit()))
                    .endAt(getEnd(triggerCalendarInterval.timeLimit()))
                    .withDescription(triggerCalendarInterval.description());

            JobDataMap jobDataMap = buildJobDataMap(triggerCalendarInterval.dataMap());
            if (null != jobDataMap) {
                simpleTriggerBuilder.usingJobData(jobDataMap);
            }
            //触发器包含、排除 日历
            String modifiedByCalendar = triggerCalendarInterval.modifiedByCalendar();
            if (StringUtils.isNotEmpty(modifiedByCalendar)) {
                simpleTriggerBuilder.modifiedByCalendar(modifiedByCalendar);
            }
            return (CalendarIntervalTrigger) simpleTriggerBuilder.forJob(jobDetail.getKey()).build();

        } catch (Exception e) {
            throw new MicroRuntimeException(QrtzError.trigger_create_failed, e);
        }

    }

    /**
     * 获取触发器名称,使用类名加触发器名称唯一
     *
     * @return
     */
    public String getName(JobDetail jobDetail, TriggerCalendarInterval triggerCalendarInterval) {
        String name = triggerCalendarInterval.name();
        return buildRealName(jobDetail, name);
    }
}

定时任务相关管理

java
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.commnetsoft.commons.Pager;
import com.commnetsoft.commons.utils.DateUtils;
import com.commnetsoft.commons.utils.StringUtils;
import com.commnetsoft.core.utils.PagerUtils;
import com.commnetsoft.core.utils.SpringContextUtil;
import com.commnetsoft.dao.QrtzTriggerDefaultDao;
import com.commnetsoft.model.QrtzTaskLogPo;
import com.commnetsoft.model.QrtzTaskRunLogPo;
import com.commnetsoft.model.QrtzTriggerDefaultPo;
import com.commnetsoft.quartz.model.*;
import org.omg.CORBA.Object;
import org.quartz.Calendar;
import org.quartz.*;
import org.quartz.impl.calendar.BaseCalendar;
import org.quartz.impl.matchers.GroupMatcher;
import org.quartz.impl.triggers.CalendarIntervalTriggerImpl;
import org.quartz.impl.triggers.CronTriggerImpl;
import org.quartz.impl.triggers.DailyTimeIntervalTriggerImpl;
import org.quartz.impl.triggers.SimpleTriggerImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.text.ParseException;
import java.util.*;

/**
 * @author luos
 * @date 2019/5/14
 */
@Service
public class TaskService {
    private Logger log = LoggerFactory.getLogger(TaskService.class);

    @Autowired
    private Scheduler scheduler;

    @Autowired
    private TaskInitService taskInitService;

    @Autowired
    private QrtzTriggerDefaultDao qrtzTriggerDefaultDao;

    @Autowired
    private QrtzTaskRunLogService qrtzTaskRunLogService;

    @Autowired
    private QrtzTaskLogService qrtzTaskLogService;

    /**
     * 任务已经存在于调度器中 新增或修改触发器
     *
     * @param jobDetail
     * @param trigger
     */
    public void modifyTrigger(JobDetail jobDetail, Trigger trigger) {
        try {
            //处理 包含/排除 日历
            addCalendarName(trigger);
            if (!checkTriggerExists(trigger.getKey())) {
                addJob(jobDetail);
                addTrigger(trigger);
            } else {
                updateJob(jobDetail, trigger);
                log.info("该定时任务({})的触发器({})已经存在", jobDetail.getKey().getName(), trigger.getKey().getName());
            }
        } catch (SchedulerException e) {
            log.error("类名不存在或执行表达式错误,exception:{}", e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 任务 注册到 调度器中
     *
     * @param jobDetail
     */
    public void addJob(JobDetail jobDetail) {
        try {
            scheduler.addJob(jobDetail, true);
        } catch (SchedulerException e) {
            log.error("类名不存在或执行表达式错误,exception:{}", e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 为 任务增加触发器
     *
     * @param trigger
     */
    public void addTrigger(Trigger trigger) {
        try {
            //处理 包含/排除 日历
            addCalendarName(trigger);
            scheduler.scheduleJob(trigger);
        } catch (SchedulerException e) {
            log.error("类名不存在或执行表达式错误,exception:{}", e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 新的定时任务绑定触发器 注册到 触发器
     *
     * @param jobDetail
     */
    public void addNewJob(JobDetail jobDetail, Trigger trigger) {
        try {
            //处理 包含/排除 日历
            addCalendarName(trigger);
            scheduler.scheduleJob(jobDetail, trigger);
        } catch (SchedulerException e) {
            log.error("类名不存在或执行表达式错误,exception:{}", e.getMessage());
            e.printStackTrace();
        }
    }


    /**
     * 修改定时任务
     *
     * @param jobDetail
     * @param trigger
     */
    public void updateJob(JobDetail jobDetail, Trigger trigger) {
        try {
            //处理 包含/排除 日历
            addCalendarName(trigger);

            if (checkTriggerExists(trigger.getKey())) {
                HashSet<Trigger> triggerSet = new HashSet<>();
                triggerSet.add(trigger);
                scheduler.scheduleJob(jobDetail, triggerSet, true);
            } else {
                log.error("该定时任务({})的触发器不存在", jobDetail.getKey().getName());
            }
        } catch (SchedulerException e) {
            log.error("类名不存在或执行表达式错误,exception:{}", e.getMessage());
            e.printStackTrace();
        }
    }

    /**
     * 通过jobName 和 组名删除任务
     *
     * @param jobName
     * @param jobGroup
     */
    public void delJob(String jobName, String jobGroup) {
        try {
            JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
            if (checkJobExists(jobKey)) {
                scheduler.deleteJob(jobKey);
                log.info("delete Job, jobGroup:{}, jobName:{}", jobGroup, jobName);
            }
        } catch (SchedulerException e) {
            log.error(e.getMessage());
        }
    }


    /**
     * 通过jjobKeys 删除多个任务
     */
    public void delJobs(List<JobKey> jobKeys) {
        try {
            scheduler.deleteJobs(jobKeys);
        } catch (SchedulerException e) {
            log.error(e.getMessage());
        }
    }


    /**
     * 通过triggerName 和 组名删除任务的触发器
     *
     * @param triggerName
     * @param groupName
     */
    public void delTigger(String triggerName, String groupName) {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, groupName);
            if (checkTriggerExists(triggerKey)) {
                scheduler.unscheduleJob(TriggerKey.triggerKey(triggerName, groupName));
                log.info("delete Tigger, groupName:{}, triggerName:{}", groupName, triggerName);
            }
        } catch (SchedulerException e) {
            log.error(e.getMessage());
        }
    }


    /**
     * 通过calendarName 删除 日历排除机制
     *
     * @param calendarName
     */
    public void delCalendar(String calendarName) {
        try {
            Calendar calendar = scheduler.getCalendar(calendarName);
            if (null != calendar) {
                scheduler.deleteCalendar(calendarName);
                log.info("delete calendar, calendarName:{}", calendarName);
            }
        } catch (SchedulerException e) {
            log.error(e.getMessage());
        }
    }


    /**
     * 验证触发器是否存在
     *
     * @param triggerKey
     * @throws SchedulerException
     */
    public boolean checkTriggerExists(TriggerKey triggerKey) throws SchedulerException {
        return scheduler.checkExists(triggerKey);
    }

    /**
     * 验证任务是否存在
     *
     * @param jobKey
     * @throws SchedulerException
     */
    public boolean checkJobExists(JobKey jobKey) throws SchedulerException {
        return scheduler.checkExists(jobKey);
    }


    /**
     * 新增/更新 处理 包含/排除 日历
     *
     * @param trigger
     */

    public void addCalendarName(Trigger trigger) {
        try {
            String calendarName = trigger.getCalendarName();
            if (StringUtils.isNotBlank(calendarName)) {
                Calendar calendar = scheduler.getCalendar(calendarName);
                Object bean = SpringContextUtil.getBean(calendarName);
                BaseCalendar m = (BaseCalendar) bean;
                if (null == calendar) {
                    scheduler.addCalendar(calendarName, m, false, false);
                } else {
                    scheduler.addCalendar(calendarName, m, true, true);
                }
            }
            log.info("触发器[{}] 的 calendarName:{},为空,无特殊日期设置任务执行", trigger.getKey().getName(), calendarName);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }

    }

    /**
     * 暂停定时任务
     *
     * @param jobName
     * @param jobGroup
     */
    public void pauseJob(String jobName, String jobGroup) {
        JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
        try {
            if (checkJobExists(jobKey)) {
                scheduler.pauseJob(jobKey);
                log.info("暂停 job success, triggerKey:{},jobGroup:{}, jobName:{}", jobKey, jobGroup, jobName);
            }
        } catch (SchedulerException e) {
            log.error(e.getMessage());
        }
    }


    /**
     * 重新恢复任务定时任务
     *
     * @param jobName
     * @param jobGroup
     */
    public void resumeJob(String jobName, String jobGroup) {
        JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
        try {
            if (checkJobExists(jobKey)) {
                scheduler.resumeJob(jobKey);
                log.info("恢复 job success, triggerKey:{},jobGroup:{}, jobName:{}", jobKey, jobGroup, jobName);
            }
        } catch (SchedulerException e) {
            log.error(e.getMessage());
        }
    }

    /**
     * 暂停任务的触发器
     *
     * @param triggerName
     * @param triggerGroup
     */
    public void pauseTrigger(String triggerName, String triggerGroup, String uid) {
        TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroup);
        try {
            if (checkTriggerExists(triggerKey)) {
                scheduler.pauseTrigger(triggerKey);
                log.info("暂停 trigger success, triggerKey:{},triggerName:{}, triggerGroup:{}", triggerKey, triggerName, triggerGroup);
            }
            if (StringUtils.isNotBlank(uid)) {
                Trigger trigger = scheduler.getTrigger(triggerKey);
                //写入操作日志
                addOperationLog(trigger.getJobKey().getName(), trigger.getJobKey().getGroup(), triggerName, triggerGroup, JSON.toJSONString(trigger), uid, QrtzTaskLogPo.operation_update);
            }
        } catch (SchedulerException e) {
            log.error(e.getMessage());
        }
    }

    /**
     * 重新恢复任务的触发器
     *
     * @param triggerName
     * @param triggerGroup
     */
    public void resumeTrigger(String triggerName, String triggerGroup, String uid) {
        TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroup);
        try {
            if (checkTriggerExists(triggerKey)) {
                scheduler.resumeTrigger(triggerKey);
                log.info("恢复 trigger success, triggerKey:{},triggerName:{}, triggerGroup:{}", triggerKey, triggerName, triggerGroup);
            }

            if (StringUtils.isNotBlank(uid)) {
                Trigger trigger = scheduler.getTrigger(triggerKey);
                //写入操作日志
                addOperationLog(trigger.getJobKey().getName(), trigger.getJobKey().getGroup(), triggerName, triggerGroup, JSON.toJSONString(trigger), uid, QrtzTaskLogPo.operation_update);
            }
        } catch (SchedulerException e) {
            log.error(e.getMessage());
        }
    }

    /**
     * 根据定时任务key 获取定时任务注册的所有触发器
     *
     * @param jobName
     * @param jobGroup
     * @return
     */
    public List<? extends Trigger> getJobTrigger(String jobName, String jobGroup) throws SchedulerException {
        JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
        List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
        return triggers;

    }


    /**
     * 根据触发器key 获取单个触发器
     *
     * @return
     */
    public Trigger getSingleTrigger(String triggerName, String triggerGroup) throws SchedulerException {
        TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroup);
        Trigger trigger = scheduler.getTrigger(triggerKey);
        return trigger;

    }

    /**
     * 获取调度器下的所有JobKey
     *
     * @return
     */
    public List<JobKey> JobKeys() {
        List<JobKey> list = new ArrayList<>();
        try {
            for (String groupJob : scheduler.getJobGroupNames()) {
                Set<JobKey> jobKeys = scheduler.getJobKeys(GroupMatcher.<JobKey>groupEquals(groupJob));
                list.addAll(jobKeys);
            }
        } catch (SchedulerException e) {
            e.printStackTrace();
        }

        return list;
    }

    /**
     * 获取调度器下的所有任务列表
     *
     * @return
     */
    public List<TaskInfoDto> jobList() {
        List<TaskInfoDto> list = new ArrayList<>();
        try {
            for (String groupJob : scheduler.getJobGroupNames()) {
                for (JobKey jobKey : scheduler.getJobKeys(GroupMatcher.<JobKey>groupEquals(groupJob))) {
                    List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
                    for (Trigger trigger : triggers) {
                        JobDetail jobDetail = scheduler.getJobDetail(jobKey);
                        TaskInfoDto info = conver(jobDetail, trigger);
                        list.add(info);
                    }
                }
            }
        } catch (SchedulerException e) {
            e.printStackTrace();
        }

        return list;
    }


    public TaskInfoDto conver(JobDetail jobDetail, Trigger trigger) throws SchedulerException {
        Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
        JobKey jobKey = jobDetail.getKey();
        String cronExpression = "", createTime = "";
        Date endTime = null;
        Date startTime = null;
        TaskInfoDto info = new TaskInfoDto();
        //简单触发器
        if (trigger instanceof SimpleTrigger) {
            SimpleTrigger simpleTrigger = (SimpleTrigger) trigger;
            endTime = simpleTrigger.getEndTime();
            startTime = simpleTrigger.getStartTime();
            int repeatCount = simpleTrigger.getRepeatCount();
            long repeatInterval = simpleTrigger.getRepeatInterval();

            info.setType(QrtzTriggerDefaultPo.tigger_simple);
            info.setRepeatCount(repeatCount);
            info.setRepeatInterval(repeatInterval);
        }
        //cron表达式触发器
        if (trigger instanceof CronTrigger) {
            CronTrigger cronTrigger = (CronTrigger) trigger;
            cronExpression = cronTrigger.getCronExpression();
            endTime = cronTrigger.getEndTime();
            startTime = cronTrigger.getStartTime();

            info.setType(QrtzTriggerDefaultPo.tigger_cron);
            info.setCronExpression(cronExpression);
        }

        //日历触发器
        if (trigger instanceof CalendarIntervalTrigger) {
            CalendarIntervalTrigger calendarTrigger = (CalendarIntervalTrigger) trigger;
            int repeatInterval = calendarTrigger.getRepeatInterval();
            String repeatIntervalUnit = calendarTrigger.getRepeatIntervalUnit().toString();
            endTime = calendarTrigger.getEndTime();
            startTime = calendarTrigger.getStartTime();

            info.setInterval(repeatInterval);
            info.setRepeatIntervalUnit(repeatIntervalUnit);
            info.setType(QrtzTriggerDefaultPo.tigger_calendar);
            info.setCronExpression(cronExpression);
        }
        //日期触发器
        if (trigger instanceof DailyTimeIntervalTrigger) {
            DailyTimeIntervalTrigger dtTrigger = (DailyTimeIntervalTrigger) trigger;
            endTime = dtTrigger.getEndTime();
            startTime = dtTrigger.getStartTime();
            int repeatCount = dtTrigger.getRepeatCount();
            Set<Integer> daysOfWeek = dtTrigger.getDaysOfWeek();
            int interval = dtTrigger.getRepeatInterval();
            String repeatIntervalUnit = dtTrigger.getRepeatIntervalUnit().toString();
            TimeOfDay startTimeOfDay = dtTrigger.getStartTimeOfDay();
            TimeOfDay endTimeOfDay = dtTrigger.getEndTimeOfDay();
            if (null != startTimeOfDay) {
                info.setStartTimeOfDay(startTimeOfDay.getHour() + ":" + startTimeOfDay.getMinute() + ":" + startTimeOfDay.getSecond());
            }
            if (null != endTimeOfDay) {
                info.setEndTimeOfDay(endTimeOfDay.getHour() + ":" + endTimeOfDay.getMinute() + ":" + endTimeOfDay.getSecond());
            }
            info.setInterval(interval);
            info.setRepeatIntervalUnit(repeatIntervalUnit);
            info.setRepeatCount(repeatCount);
            info.setDaysOfWeek(daysOfWeek);
            info.setType(QrtzTriggerDefaultPo.tigger_daily);
            info.setCronExpression(cronExpression);
        }

        info.setJobName(jobKey.getName());
        info.setJobGroup(jobKey.getGroup());
        info.setTriggerName(trigger.getKey().getName());
        info.setTriggerGroup(trigger.getKey().getGroup());
        info.setJobDescription(jobDetail.getDescription());
        info.setJobStatus(triggerState.name());
        info.setEndTime(endTime);
        info.setStartTime(startTime);


        return info;
    }

    public TaskInfoDto jobInfo(JobInfoQueryDto query) {
        String jobname = query.getJobName(),
                jobgroup = query.getJobGroup(),
                tigname = query.getTriggerName(),
                tiggroup = query.getTriggerGroup();
        JobKey jobKey = JobKey.jobKey(jobname, jobgroup);
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(tigname, tiggroup);
            JobDetail jobDetail = scheduler.getJobDetail(jobKey);
            Trigger trigger = scheduler.getTrigger(triggerKey);

            TaskInfoDto info = conver(jobDetail, trigger);
            return info;
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 运维人员后台修改任务信息
     *
     * @return
     */
    public void edit(TaskInfoDto info) {

        String jobName = info.getJobName(),
                jobGroup = info.getJobGroup(),
                cronExpression = info.getCronExpression(),
                jobDescription = info.getJobDescription(),
                triggerName = info.getTriggerName(),
                triggerGroup = info.getTriggerGroup();
        Integer type = info.getType();
        boolean isDef = taskInitService.isDefault(jobName, jobGroup, triggerName, triggerGroup);

        try {

            TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroup);
            JobKey jobKey = JobKey.jobKey(jobName, jobGroup);
            Trigger trigger = scheduler.getTrigger(triggerKey);
            if (!isDef) {
                //如果没有默认值,将信息更新到默认值表中,作为 还原默认值数据
                QrtzTriggerDefaultPo qd = new QrtzTriggerDefaultPo();
                qd.setSchedname(scheduler.getSchedulerName());
                qd.setJobname(jobName);
                qd.setJobgroup(jobGroup);
                qd.setTriggername(triggerName);
                qd.setTriggergroup(triggerGroup);
                qd.setTriggerdata(JSON.toJSONString(trigger));
                qd.setTriggertype(type);
                qd.setCreatetime(new Date());
                qrtzTriggerDefaultDao.insertSelective(qd);
            }
            if (!checkJobExists(jobKey)) {
                log.info("edit job fail, job is not exist, jobGroup:{}, jobName:{}", jobGroup, jobName);
            }
            JobDetail jobDetail = scheduler.getJobDetail(jobKey);
            HashSet<Trigger> triggerSet = new HashSet<>();
            if (trigger instanceof CronTrigger) {
                CronTriggerImpl cronTrigger = (CronTriggerImpl) trigger;
                //更改表达式
                cronTrigger.setCronExpression(cronExpression);
                jobDetail.getJobBuilder().withDescription(jobDescription);
                triggerSet.add(cronTrigger);
            }
            if (trigger instanceof SimpleTrigger) {
                SimpleTriggerImpl simpleTrigger = (SimpleTriggerImpl) trigger;
                simpleTrigger.setRepeatInterval(info.getRepeatInterval());
                if (info.getRepeatCount() != 0) {
                    simpleTrigger.setRepeatCount(info.getRepeatCount());
                }
                triggerSet.add(simpleTrigger);
            }
            if (trigger instanceof CalendarIntervalTrigger) {
                CalendarIntervalTriggerImpl calendarTrigger = (CalendarIntervalTriggerImpl) trigger;
                calendarTrigger.setRepeatInterval(info.getInterval());
                calendarTrigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.valueOf(info.getRepeatIntervalUnit()));
                triggerSet.add(calendarTrigger);
            }
            if (trigger instanceof DailyTimeIntervalTrigger) {
                DailyTimeIntervalTriggerImpl dailyTrigger = (DailyTimeIntervalTriggerImpl) trigger;
                dailyTrigger.setDaysOfWeek(info.getDaysOfWeek());
                dailyTrigger.setRepeatInterval(info.getInterval());
                dailyTrigger.setRepeatIntervalUnit(DateBuilder.IntervalUnit.valueOf(info.getRepeatIntervalUnit()));
                if (info.getRepeatCount() != 0) {
                    dailyTrigger.setRepeatCount(info.getRepeatCount());
                }
                triggerSet.add(dailyTrigger);
            }
            scheduler.scheduleJob(jobDetail, triggerSet, true);

            if (StringUtils.isNotBlank(info.getIdmuid())) {
                //写入操作日志
                addOperationLog(jobName, jobGroup, triggerName, triggerGroup, JSON.toJSONString(trigger), info.getIdmuid(), QrtzTaskLogPo.operation_update);
            }
        } catch (SchedulerException e) {
            e.printStackTrace();
            log.error("类名不存在或执行表达式错误,exception:{}", e.getMessage());
        } catch (ParseException e) {
            e.printStackTrace();
            log.error("更改触发器执行表达式错误,exception:{}", e.getMessage());
        }
    }

    /**
     * 根据job名 组 当前立即执行某一任务
     *
     * @param name
     * @param group
     */
    public void runTaskImmediately(String name, String group) {
        try {
            JobKey jobKey = JobKey.jobKey(name, group);
            JobDetail jobDetail = scheduler.getJobDetail(jobKey);
            if (null == jobDetail) {
                throw new SchedulerException("任务未加入调度器中");
            }
            scheduler.triggerJob(JobKey.jobKey(name, group));
        } catch (SchedulerException e) {
            e.printStackTrace();
            log.error("类名不存在或执行表达式错误,exception:{}", e.getMessage());
        }
    }

    /**
     * 恢复任务触发器默认值
     *
     * @param rd
     */
    public void restoreDefault(RestoreDefaultDto rd) {

        String jobname = rd.getJobName(),
                jobgroup = rd.getJobGroup(),
                tigname = rd.getTriggerName(),
                tiggroup = rd.getTriggerGroup();

        try {
            QrtzTriggerDefaultPo qrtzTriggerDefaultPo = new QrtzTriggerDefaultPo();
            qrtzTriggerDefaultPo.setJobname(jobname);
            qrtzTriggerDefaultPo.setJobgroup(jobgroup);
            qrtzTriggerDefaultPo.setTriggername(tigname);
            qrtzTriggerDefaultPo.setTriggergroup(tiggroup);
            QrtzTriggerDefaultPo qd = qrtzTriggerDefaultDao.selectOne(qrtzTriggerDefaultPo);

            String triggerJson = qd.getTriggerdata();
            JSONObject jsonObject = JSON.parseObject(triggerJson);
            JobKey jobKey = JobKey.jobKey(jobname, jobgroup);
            TriggerKey triggerKey = TriggerKey.triggerKey(tigname, tiggroup);
            Trigger trigger = scheduler.getTrigger(triggerKey);
            if (trigger instanceof SimpleTrigger) {
                SimpleTriggerImpl simple = (SimpleTriggerImpl) trigger;
                String repeatCount = jsonObject.getString("repeatCount");
                String repeatInterval = jsonObject.getString("repeatInterval");

                if (StringUtils.isNotBlank(repeatCount)) {
                    simple.setRepeatCount(Integer.valueOf(repeatCount));
                }
                simple.setRepeatInterval(Integer.valueOf(repeatInterval));

            }

            if (trigger instanceof CronTrigger) {
                CronTriggerImpl cron = (CronTriggerImpl) trigger;
                String cronExpression = jsonObject.getString("cronExpression");
                //更改表达式
                cron.setCronExpression(cronExpression);
            }
            if (trigger instanceof CalendarIntervalTrigger) {
                CalendarIntervalTriggerImpl calendar = (CalendarIntervalTriggerImpl) trigger;
                String repeatInterval = jsonObject.getString("repeatInterval");
                String repeatIntervalUnit = jsonObject.getString("repeatIntervalUnit");
                calendar.setRepeatInterval(Integer.valueOf(repeatInterval));
                calendar.setRepeatIntervalUnit(DateBuilder.IntervalUnit.valueOf(repeatIntervalUnit));
            }
            if (trigger instanceof DailyTimeIntervalTrigger) {
                DailyTimeIntervalTriggerImpl daily = (DailyTimeIntervalTriggerImpl) trigger;
                String repeatCount = jsonObject.getString("repeatCount");
                String repeatInterval = jsonObject.getString("repeatInterval");
                String repeatIntervalUnit = jsonObject.getString("repeatIntervalUnit");
                String daysOfWeek = jsonObject.getString("daysOfWeek");
                List<Integer> list = JSON.parseArray(daysOfWeek, Integer.class);
                Set<Integer> set = new HashSet<>(list);
                daily.setRepeatCount(Integer.valueOf(repeatCount));
                daily.setRepeatInterval(Integer.valueOf(repeatInterval));
                daily.setRepeatIntervalUnit(DateBuilder.IntervalUnit.valueOf(repeatIntervalUnit));
                daily.setDaysOfWeek(set);
            }

            JobDetail jobDetail = scheduler.getJobDetail(jobKey);
            updateJob(jobDetail, trigger);

            if (StringUtils.isNotBlank(rd.getUid())) {
                //写入操作日志
                addOperationLog(jobname, jobgroup, tigname, tiggroup, JSON.toJSONString(trigger), rd.getUid(), QrtzTaskLogPo.operation_update);
            }
        } catch (SchedulerException e) {
            e.printStackTrace();
        } catch (ParseException e) {
            e.printStackTrace();
        }


    }

    public TaskInfoDto jobDefault(RestoreDefaultDto rd) {

        String jobname = rd.getJobName(),
                jobgroup = rd.getJobGroup(),
                tigname = rd.getTriggerName(),
                tiggroup = rd.getTriggerGroup();
        String schedulername = SpringContextUtil.getApplicationContext().getEnvironment().getProperty("spring.application.name");
        QrtzTriggerDefaultPo qrtzTriggerDefaultPo = new QrtzTriggerDefaultPo();
        qrtzTriggerDefaultPo.setSchedname(schedulername);
        qrtzTriggerDefaultPo.setJobname(jobname);
        qrtzTriggerDefaultPo.setJobgroup(jobgroup);
        qrtzTriggerDefaultPo.setTriggername(tigname);
        qrtzTriggerDefaultPo.setTriggergroup(tiggroup);
        QrtzTriggerDefaultPo qd = qrtzTriggerDefaultDao.selectOne(qrtzTriggerDefaultPo);

        if (ObjectUtils.isEmpty(qd)) {
            return null;
        }

        TaskInfoDto taskInfo = new TaskInfoDto();
        taskInfo.setJobName(jobname);
        taskInfo.setJobGroup(jobgroup);
        taskInfo.setTriggerName(tigname);
        taskInfo.setTriggerGroup(tiggroup);
        JSONObject jsonObject = JSON.parseObject(qd.getTriggerdata());
        if (qd.getTriggertype().equals(QrtzTriggerDefaultPo.tigger_simple)) {
            String repeatCount = jsonObject.getString("repeatCount");
            String repeatInterval = jsonObject.getString("repeatInterval");

            taskInfo.setRepeatCount(Integer.valueOf(repeatCount));
            taskInfo.setRepeatInterval(Integer.valueOf(repeatInterval));
            taskInfo.setType(QrtzTriggerDefaultPo.tigger_simple);
        }

        if (qd.getTriggertype().equals(QrtzTriggerDefaultPo.tigger_cron)) {
            String cronExpression = jsonObject.getString("cronExpression");
            taskInfo.setCronExpression(cronExpression);
            taskInfo.setType(QrtzTriggerDefaultPo.tigger_cron);
        }

        if (qd.getTriggertype().equals(QrtzTriggerDefaultPo.tigger_calendar)) {
            String repeatInterval = jsonObject.getString("repeatInterval");
            String repeatIntervalUnit = jsonObject.getString("repeatIntervalUnit");
            taskInfo.setInterval(Integer.valueOf(repeatInterval));
            taskInfo.setRepeatIntervalUnit(repeatIntervalUnit);
            taskInfo.setType(QrtzTriggerDefaultPo.tigger_cron);
        }

        if (qd.getTriggertype().equals(QrtzTriggerDefaultPo.tigger_daily)) {
            String repeatCount = jsonObject.getString("repeatCount");
            String repeatInterval = jsonObject.getString("repeatInterval");
            String repeatIntervalUnit = jsonObject.getString("repeatIntervalUnit");
            String daysOfWeek = jsonObject.getString("daysOfWeek");
            List<Integer> list = JSON.parseArray(daysOfWeek, Integer.class);
            Set<Integer> set = new HashSet<>(list);
            taskInfo.setRepeatCount(Integer.valueOf(repeatCount));
            taskInfo.setInterval(Integer.valueOf(repeatInterval));
            taskInfo.setRepeatIntervalUnit(repeatIntervalUnit);
            taskInfo.setType(QrtzTriggerDefaultPo.tigger_cron);
            taskInfo.setDaysOfWeek(set);
        }
        return taskInfo;
    }

    public Pager<RunLogDto> getRunLog(RunLogPageQueryDto runLogPageQueryDto) {

        Pager<QrtzTaskRunLogPo> runLog = qrtzTaskRunLogService.getRunLog(runLogPageQueryDto);
        Pager<RunLogDto> runLogVoPager = PagerUtils.cast(runLog, RunLogDto.class);
        return runLogVoPager;
    }

    /**
     * 写入运维操作日志
     *
     * @param jobname
     * @param jobgroup
     * @param triggername
     * @param triggergroup
     * @param triggerdata
     * @param uid
     * @param type
     */
    public void addOperationLog(String jobname, String jobgroup, String triggername, String triggergroup, String triggerdata, String uid, String type) {
        try {
            QrtzTaskLogPo qrtzTaskLogPo = new QrtzTaskLogPo();
            qrtzTaskLogPo.setSchedname(scheduler.getSchedulerName());
            qrtzTaskLogPo.setJobname(jobname);
            qrtzTaskLogPo.setJobgroup(jobgroup);
            qrtzTaskLogPo.setTriggername(triggername);
            qrtzTaskLogPo.setTriggergroup(triggergroup);
            qrtzTaskLogPo.setTriggerdata(triggerdata);
            qrtzTaskLogPo.setCreatetime(new Date());
            qrtzTaskLogPo.setCreateuser(uid);
            qrtzTaskLogPo.setOptype(type);
            qrtzTaskLogService.addLog(qrtzTaskLogPo);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取最近指定次数的执行时间
     * @param cronExpression cron表达式
     * @param times 次数
     * @param dateFormat 返回的时间格式
     * @return java.util.List<java.lang.String>
     * @author wuzm
     * @date 2020/11/2
     */
    public List<String> getNextTimes(String cronExpression, int times, String dateFormat) throws ParseException {
        List<String> dateList = new ArrayList<>();
        if(times > 0){
            CronExpression cron = new CronExpression(cronExpression);
            Date lastRun = new Date();
            for (int i = 0; i < times; i++) {
                lastRun = cron.getNextValidTimeAfter(lastRun);
                dateList.add(DateUtils.parseDateToString(lastRun, dateFormat));
            };
        }
        return dateList;
    }
}

定时任务线程池

java
import org.quartz.SchedulerConfigException;
import org.quartz.spi.ThreadPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;

/**
 * <br>
 *
 * @author luos
 * @date 2020/10/14
 */
@Component
public class TaskPool implements ThreadPool {
    private Logger logger = LoggerFactory.getLogger(TaskPool.class);

    ExecutorService executorService;

    public void setThreadCount(int count) {
    }


    @Override
    public boolean runInThread(Runnable runnable) {
        Assert.state(this.executorService != null, "No TaskExecutor available");
        try {
            this.executorService.execute(runnable);
            return true;
        } catch (RejectedExecutionException ex) {
            logger.error("Task has been rejected by TaskExecutor", ex);
            return false;
        }

    }

    @Override
    public int blockForAvailableThreads() {
        return 1;
    }

    @Override
    public void initialize() throws SchedulerConfigException {
        this.executorService = Executors.newCachedThreadPool();
        if (this.executorService == null) {
            throw new SchedulerConfigException("No local Executor found for configuration - " +
                    "'taskExecutor' property must be set on SchedulerFactoryBean");
        }
    }

    @Override
    public void shutdown(boolean waitForJobsToComplete) {
        executorService.shutdownNow();
    }

    @Override
    public int getPoolSize() {
        return -1;
    }

    @Override
    public void setInstanceId(String schedInstId) {

    }

    @Override
    public void setInstanceName(String schedName) {

    }


}